package com.dcstudy.redis.cachepenetration.bloomfilter;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

import java.util.ArrayList;
import java.util.List;

/**
 * @auther zzyy
 * @create 2021-05-20 16:43
 *
 * 缓存穿透解决方案 - google guava 单机版布隆过滤器
 * 谷歌 guava 布隆过滤器实现
 * 误判率证明:
 * 当 fpp 设置为 0.03时, 10w 的数据 有 3033条几率被误判了, 误判率为 0.03
 */
public class GuavaBloomfilterDemo {
    public static final int _1W = 10000;
    /**
     * 布隆过滤器里预计要插入多少数据
     */
    public static int size = 100 * _1W;
    /**
     * 误判率,它越小误判的个数也就越少(思考，是不是可以设置的无限小，没有误判岂不更好)
     */
    public static double fpp = 0.01;

    /**
     * helloworld入门
     */
    public void bloomFilter() {
        // 创建一个 容量为100 的布隆过滤器对象
        BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(), 100);
        // 判断指定元素是否存在
        System.out.println(filter.mightContain(1));
        System.out.println(filter.mightContain(2));
        // 将元素添加进布隆过滤器
        filter.put(1);
        filter.put(2);
        System.out.println(filter.mightContain(1));
        System.out.println(filter.mightContain(2));

    }

    /**
     * 误判率演示+源码分析
     */
    public void bloomFilter2() {
        // 构建一个容量为 size, 误判率为fpp 的布隆过滤器,fpp表示百分之XXX 例如 这里使用的是 0.01%
        BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);

        //1 先往布隆过滤器里面插入100万的样本数据
        for (int i = 0; i < size; i++) {
            bloomFilter.put(i);
        }

       /* List<Integer> listSample = new ArrayList<>(size);
        //2 这100万的样本数据，是否都在布隆过滤器里面存在？
        for (int i = 0; i < size; i++)
        {
            if (bloomFilter.mightContain(i)) {
                listSample.add(i);
                continue;
            }
        }
        System.out.println("存在的数量：" + listSample.size());*/

        //3 故意取10万个不在过滤器里的值，看看有多少个会被认为在过滤器里,误判率演示
        List<Integer> list = new ArrayList<>(10 * _1W);

        for (int i = size + 1; i < size + 100000; i++) {
            if (bloomFilter.mightContain(i)) {
                System.out.println(i + "\t" + "被误判了.");
                list.add(i);
            }
        }
        System.out.println("误判的数量：" + list.size());
    }

    public static void main(String[] args) {
        GuavaBloomfilterDemo guavaBloomfilterDemo = new GuavaBloomfilterDemo();
        // helloword
        guavaBloomfilterDemo.bloomFilter();
        // 演示误判
        guavaBloomfilterDemo.bloomFilter2();
    }
}
